From b9ed957af38b19538d483c90af21676b0f6c329c Mon Sep 17 00:00:00 2001 From: =?utf8?q?Timm=20B=C3=A4der?= Date: Tue, 12 May 2020 20:11:13 +0200 Subject: [PATCH] gl renderer: Fix nested rounded clip rendering If the inner clip intersects with the corners of the outer clip, we potentially need a texture. We should add more fine-grained checks for this in the future though. Test case included. --- gsk/gl/gskglrenderer.c | 61 +++++++++++++++++- .../gsk/compare/nested-rounded-clips.node | 35 ++++++++++ .../gsk/compare/nested-rounded-clips.png | Bin 0 -> 469 bytes testsuite/gsk/meson.build | 1 + 4 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 testsuite/gsk/compare/nested-rounded-clips.node create mode 100644 testsuite/gsk/compare/nested-rounded-clips.png diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c index ac8680ba0f..f45c4d5709 100644 --- a/gsk/gl/gskglrenderer.c +++ b/gsk/gl/gskglrenderer.c @@ -1129,6 +1129,35 @@ render_linear_gradient_node (GskGLRenderer *self, load_vertex_data (ops_draw (builder, NULL), node, builder); } +static inline gboolean +rounded_inner_rect_contains_rect (const GskRoundedRect *rounded, + const graphene_rect_t *rect) +{ + const graphene_rect_t *rounded_bounds = &rounded->bounds; + graphene_rect_t inner; + float offset_x, offset_y; + + /* TODO: This is pretty conservative and we could to further, more + * fine-grained checks to avoid offscreen drawing. */ + + offset_x = MAX (rounded->corner[GSK_CORNER_TOP_LEFT].width, + rounded->corner[GSK_CORNER_BOTTOM_LEFT].width); + offset_y = MAX (rounded->corner[GSK_CORNER_TOP_LEFT].height, + rounded->corner[GSK_CORNER_TOP_RIGHT].height); + + + inner.origin.x = rounded_bounds->origin.x + offset_x; + inner.origin.y = rounded_bounds->origin.y + offset_y; + inner.size.width = rounded_bounds->size.width - offset_x - + MAX (rounded->corner[GSK_CORNER_TOP_RIGHT].width, + rounded->corner[GSK_CORNER_BOTTOM_RIGHT].width); + inner.size.height = rounded_bounds->size.height - offset_y - + MAX (rounded->corner[GSK_CORNER_BOTTOM_LEFT].height, + rounded->corner[GSK_CORNER_BOTTOM_RIGHT].height); + + return graphene_rect_contains_rect (&inner, rect); +} + static inline void render_clipped_child (GskGLRenderer *self, RenderOpBuilder *builder, @@ -1141,6 +1170,34 @@ render_clipped_child (GskGLRenderer *self, ops_transform_bounds_modelview (builder, clip, &transformed_clip); + /* Intersection might end up having rounded corners again */ + if (!gsk_rounded_rect_is_rectilinear (builder->current_clip)) + { + if (!rounded_inner_rect_contains_rect (builder->current_clip, + &transformed_clip)) + { + /* well fuck */ + gboolean is_offscreen; + TextureRegion region; + + ops_push_clip (builder, &child_clip); + if (!add_offscreen_ops (self, builder, &child->bounds, + child, + ®ion, &is_offscreen, + RESET_OPACITY | RESET_CLIP)) + g_assert_not_reached (); + + ops_pop_clip (builder); + + ops_set_program (builder, &self->programs->blit_program); + ops_set_texture (builder, region.texture_id); + + load_offscreen_vertex_data (ops_draw (builder, NULL), child, builder); + return; + } + } + + /* Simple case: */ graphene_rect_intersection (&transformed_clip, &builder->current_clip->bounds, &intersection); @@ -1182,8 +1239,8 @@ render_rounded_clip_node (GskGLRenderer *self, if (!ops_has_clip (builder)) need_offscreen = FALSE; - else if (graphene_rect_contains_rect (&builder->current_clip->bounds, - &transformed_clip.bounds)) + else if (rounded_inner_rect_contains_rect (builder->current_clip, + &transformed_clip.bounds)) need_offscreen = FALSE; else need_offscreen = TRUE; diff --git a/testsuite/gsk/compare/nested-rounded-clips.node b/testsuite/gsk/compare/nested-rounded-clips.node new file mode 100644 index 0000000000..98646b28f7 --- /dev/null +++ b/testsuite/gsk/compare/nested-rounded-clips.node @@ -0,0 +1,35 @@ + transform { + child: rounded-clip { + child: rounded-clip { + clip: 10 10 30 30 / 5; + child: color { + color: teal; + bounds: 12 12 26 26; + } + } + clip: 10 10 30 30 / 25 0 0 0; + } + + transform: scale(5); + } + +color { + color: black; + bounds: 55 100 40 40; +} + +color { + color: black; + bounds: 70 80 20 20; +} + +color { + color: black; + bounds: 90 70 40 40; +} + +color { + color: black; + bounds: 105 55 30 20; +} + diff --git a/testsuite/gsk/compare/nested-rounded-clips.png b/testsuite/gsk/compare/nested-rounded-clips.png new file mode 100644 index 0000000000000000000000000000000000000000..8b954e1467bbff9bb0adf07d8b9e5ec933135333 GIT binary patch literal 469 zcmeAS@N?(olHy`uVBq!ia0vp^?I6s-1|)5sdx0d_lDyqr82*Fcg1yTpGcYiAdAc}; zRLpsMXCv2P1rdjfOP(D5`?*YiXK$^$-RucGfxycn^j=S@G>ry{@|a2)xK-{zr8%aE-I??B!*Kk9fw!MDt~_8 q!@M9LzF8oD66-Q>ppdWl68E-dZoz$KirK(;V(@hJb6Mw<&;$TU60leR literal 0 HcmV?d00001 diff --git a/testsuite/gsk/meson.build b/testsuite/gsk/meson.build index e9fdc661b7..225ce98261 100644 --- a/testsuite/gsk/meson.build +++ b/testsuite/gsk/meson.build @@ -66,6 +66,7 @@ compare_render_tests = [ 'blend-invisible-child', 'transform-in-transform', 'transform-in-transform-in-transform', + 'nested-rounded-clips', ] # these are too sensitive to differences in the renderers -- 2.30.2